package com.smart.community.commons.monitor;

import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 连接池监控端点
 * @author Wu.Liang
 * @since 2024-12-19
 * @version 1.0.0
 */
@Slf4j
@Component
@Endpoint(id = "connectionpool")
public class ConnectionPoolMetricsEndpoint {
    
    private final DataSource dataSource;
    
    public ConnectionPoolMetricsEndpoint(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    /**
     * 获取连接池指标
     * 
     * @return 连接池指标
     */
    @ReadOperation
    public Map<String, Object> getConnectionPoolMetrics() {
        Map<String, Object> metrics = new HashMap<>();
        
        try {
            if (dataSource instanceof HikariDataSource) {
                HikariDataSource hikariDataSource = (HikariDataSource) dataSource;
                
                metrics.put("poolName", "HikariCP");
                metrics.put("maximumPoolSize", hikariDataSource.getMaximumPoolSize());
                metrics.put("minimumIdle", hikariDataSource.getMinimumIdle());
                metrics.put("activeConnections", hikariDataSource.getHikariPoolMXBean().getActiveConnections());
                metrics.put("idleConnections", hikariDataSource.getHikariPoolMXBean().getIdleConnections());
                metrics.put("totalConnections", hikariDataSource.getHikariPoolMXBean().getTotalConnections());
                metrics.put("threadsAwaitingConnection", hikariDataSource.getHikariPoolMXBean().getThreadsAwaitingConnection());
                metrics.put("connectionTimeout", hikariDataSource.getConnectionTimeout());
                metrics.put("idleTimeout", hikariDataSource.getIdleTimeout());
                metrics.put("maxLifetime", hikariDataSource.getMaxLifetime());
                metrics.put("validationTimeout", 5000); // HikariCP默认值
                
                // 计算连接池使用率
                double usageRate = hikariDataSource.getMaximumPoolSize() > 0 ? 
                    (double) hikariDataSource.getHikariPoolMXBean().getActiveConnections() / hikariDataSource.getMaximumPoolSize() * 100 : 0;
                metrics.put("usageRate", String.format("%.2f%%", usageRate));
                
                // 连接池状态
                String status = getHikariPoolStatus(hikariDataSource);
                metrics.put("status", status);
                
                log.debug("📊 连接池指标: {}", metrics);
            } else {
                metrics.put("error", "不支持的数据源类型: " + dataSource.getClass().getName());
                log.warn("⚠️ 不支持的数据源类型: {}", dataSource.getClass().getName());
            }
        } catch (Exception e) {
            metrics.put("error", "获取连接池指标失败: " + e.getMessage());
            log.error("❌ 获取连接池指标失败", e);
        }
        
        return metrics;
    }
    
    /**
     * 获取HikariCP连接池状态
     * 
     * @param hikariDataSource HikariCP数据源
     * @return 连接池状态
     */
    private String getHikariPoolStatus(HikariDataSource hikariDataSource) {
        int activeConnections = hikariDataSource.getHikariPoolMXBean().getActiveConnections();
        int maximumPoolSize = hikariDataSource.getMaximumPoolSize();
        
        if (activeConnections == 0) {
            return "IDLE";
        } else if (activeConnections < maximumPoolSize * 0.5) {
            return "NORMAL";
        } else if (activeConnections < maximumPoolSize * 0.8) {
            return "WARNING";
        } else {
            return "CRITICAL";
        }
    }
    
    /**
     * 获取连接池健康状态
     * 
     * @return 健康状态
     */
    @ReadOperation
    public Map<String, Object> getConnectionPoolHealth() {
        Map<String, Object> health = new HashMap<>();
        
        try {
            if (dataSource instanceof HikariDataSource) {
                HikariDataSource hikariDataSource = (HikariDataSource) dataSource;
                
                // 检查连接池是否正常
                int maximumPoolSize = hikariDataSource.getMaximumPoolSize();
                boolean isHealthy = hikariDataSource.getHikariPoolMXBean().getActiveConnections() < maximumPoolSize;
                
                health.put("status", isHealthy ? "UP" : "DOWN");
                health.put("activeConnections", hikariDataSource.getHikariPoolMXBean().getActiveConnections());
                health.put("maximumPoolSize", maximumPoolSize);
                health.put("availableConnections", maximumPoolSize - hikariDataSource.getHikariPoolMXBean().getActiveConnections());
                
                if (!isHealthy) {
                    health.put("message", "连接池已满，无法获取新连接");
                }
                
                log.debug("🏥 连接池健康状态: {}", health);
            } else {
                health.put("status", "UNKNOWN");
                health.put("message", "不支持的数据源类型");
            }
        } catch (Exception e) {
            health.put("status", "DOWN");
            health.put("message", "获取健康状态失败: " + e.getMessage());
            log.error("❌ 获取连接池健康状态失败", e);
        }
        
        return health;
    }
}
